import { LngLat, GeocoderModule, GeocoderOptions, ExtraOptions } from "./types";

/**
 * 地理编码器模块
 * 提供地址转坐标、坐标转地址、地址搜索等功能
 */

export default {
  name: "Geocoder",
  AMap: null as any,
  map: null as any,

  /**
   * 地理编码器实例
   */
  geocoder: null as any,

  /**
   * 根据输入关键字提示匹配信息实例
   */
  autocomplete: null as any,

  /**
   * 当前地图标记
   */
  marker: null as any,

  /**
   * 当前选中的经纬度
   */
  lnglat: null as LngLat | null,

  /**
   * 当前选中的地址信息
   */
  AddressInfo: null as any,

  /**
   * 事件监听器列表
   */
  eventListeners: [] as Array<{ name: string; cb: Function }>,
  /**
   * 额外参数
   */

  extra: {} as ExtraOptions,
  /**
   * 初始化地理编码器模块
   * @param options - 地理编码器配置选项
   * @returns 包含模块实例和方法的对象
   */
  init(options: GeocoderOptions = {}, extra: ExtraOptions = {}): Promise<GeocoderModule> {
    const AMap = this.AMap;
    const map = this.map;
    this.extra = extra;
    return new Promise(resolve => {
      AMap.plugin(["AMap.AutoComplete", "AMap.Geocoder"], () => {
        // 初始化地理编码器
        this.geocoder = new AMap.Geocoder({
          ...options
        });

        // 根据输入关键字提示匹配信息
        this.autocomplete = new AMap.Autocomplete({
          input: "inputAddress",
          output: "searchResult",
          city: options.city || "",
          closeResultOnScroll: false, // 页面滚动时关闭搜索结果列表 否
          citylimit: true, //是否强制限制在设置的城市内搜索
          datatype: "all" // 返回的数据类型 all-返回所有数据类型
        });

        // 绑定地图点击事件，添加标记
        AMap.Event.addListener(map, "click", (e: any) => {
          this.addMarker([e.lnglat.lng, e.lnglat.lat]);
        });

        // 绑定自动完成选择事件
        AMap.Event.addListener(this.autocomplete, "select", (e: any) => {
          this.addMarker([e.poi.location.getLng(), e.poi.location.getLat()]);
        });

        resolve({
          name: "Geocoder",
          instance: {
            geocoder: this.geocoder,
            autocomplete: this.autocomplete
          },
          events: {
            getLnglat: () => this.lnglat,
            getAddress: () => this.AddressInfo,
            on: (eventName: string, callback: Function) => this.on(eventName, callback),
            off: (eventName: string, callback?: Function) => this.off(eventName, callback)
          }
        });
      });
    });
  },

  /**
   * 订阅事件
   * @param eventName - 事件名称
   * @param callback - 回调函数
   */
  on(eventName: string, callback: Function): void {
    // 移除已存在的相同事件
    this.off(eventName);
    this.eventListeners.push({ name: eventName, cb: callback });
  },

  /**
   * 取消订阅事件
   * @param eventName - 事件名称
   * @param callback - 可选，指定要移除的回调函数
   */
  off(eventName: string, callback?: Function): void {
    this.eventListeners = this.eventListeners.filter(listener => {
      if (listener.name !== eventName) return true;
      if (callback) return listener.cb !== callback;
      return false;
    });
  },

  /**
   * 触发事件
   * @param eventName - 事件名称
   * @param data - 传递给回调函数的数据
   */
  emit(eventName: string, data?: any): void {
    this.eventListeners.filter(listener => listener.name === eventName).forEach(listener => listener.cb(data));
  },

  /**
   * 添加地图标记
   * @param lnglat - 经纬度坐标
   */
  addMarker(lnglat: LngLat): void {
    // 移除已存在的标记
    if (this.marker) {
      this.map.remove(this.marker);
    }

    // 创建新标记
    this.marker = new this.AMap.Marker({
      map: this.map,
      position: lnglat
    });

    // 添加标记到地图并设置中心
    this.map.setCenter(lnglat, true);
    this.map.setFitView([this.marker], true);

    // 保存当前经纬度
    this.lnglat = lnglat;

    // 是否开启逆地理编码
    this.extra.reverseGeocoding && this.getAddressInfo(lnglat);
  },

  /**
   * 地理编码方法 - 将地址转换为坐标
   * @param address - 地址字符串
   * @param callback - 回调函数，接收编码结果
   */
  getLocation(address: string): Promise<any> {
    if (!this.geocoder) {
      console.error("地理编码器未初始化");
      return Promise.reject(new Error("地理编码器未初始化"));
    }

    return new Promise((resolve, reject) => {
      this.geocoder.getLocation(address, (status: string, result: any) => {
        if (status === "complete" && result.info === "OK") {
          console.log("地理编码成功:", result);
          const lnglat: LngLat = [result.geocodes[0].location.getLng(), result.geocodes[0].location.getLat()];
          this.addMarker(lnglat);
          resolve(result);
        } else {
          console.error("地理编码失败:", result);
          reject(result);
        }
      });
    });
  },

  /**
   * 逆地理编码方法 - 将坐标转换为地址
   * @param lnglat - 经纬度坐标
   * @param callback - 回调函数，接收逆编码结果
   */
  getAddressInfo(lnglat: LngLat): Promise<any> {
    if (!this.geocoder) {
      console.error("地理编码器未初始化");
      return Promise.reject(new Error("地理编码器未初始化"));
    }

    return new Promise((resolve, reject) => {
      this.geocoder.getAddress(lnglat, (status: string, result: any) => {
        if (status === "complete" && result.info === "OK") {
          console.log("逆地理编码成功:", result);
          this.AddressInfo = result;
          // 触发地址更新事件
          this.emit("addressChanged", result.regeocode.formattedAddress);
          resolve(result);
        } else {
          console.error("逆地理编码失败:", result);
          reject(result);
        }
      });
    });
  }
};
